// 获取Object原型上内置方法的描述
var objDes = Object.getOwnPropertyDescriptor(Object.prototype, 'toString')
console.log('objDes', objDes) // 可以返回
// in操作符
var obj1 = new Object()
var inAssert = 'toString' in obj1
console.log(inAssert) // true

// 写屏蔽属性
Object.toString = 'i am a to string'
for (x in Object) {
  console.log(x, Object[x]) // toString i am a to string 通过重写toString内置方法,使得变得可枚举
}


// for in 或者 in 操作符，都是原型中有这个属性，就遍历或者返回true.
// 但是属性名判断的时候，得是字符串。
var obj = {a: 1}
obj.__proto__.b = 2
b in obj
// false 
// 'b' in obj
true
obj.hasOwnProperty('b')
false

// Object.keys()
function Person() {
  this.name = 'Rob'
  this.age = 31
}
Person.toString = 'dasdasda'
Person.prototype = {
  name: 'Nicholas',
  age: 29,
  job: 'soft Enfineer',
  sayName: function () {
    console.log(this.job)
  }
}
var person = new Person()
console.log(Object.keys(Person)) // toString 
console.log(Object.keys(person)) //  ["name", "age"]  只输出了实例上的属性
console.log(Object.keys(person.__proto__)) // ["name", "age", "job", "sayName"]  // 函数属性也是可以打印出来的。

console.log(Object.getOwnPropertyNames(Object)) //挂在函数对象上的属性,Object是一个构造函数,不是对象
console.log(Object.getOwnPropertyNames(Object.prototype))

// 更简单的原型语法
function Person () {}
Person.prototype = { // 重写了原型对象,constructor属性同时也改写了,此时指向Object
  name: 'lee'
}
Person.prototype = { // 虽然重新规定了constructor,但是无法复制'创建函数,生成原型时候的不可枚举属性'
  constructor: Person,
  name: 'lee'
}
Person.prototype = {name: 'lee'}
Object.defineProperty(Person.prototype, 'constructor', {
  enumerable: false,
  value: Person
})

// 原型的动态性
var friend = new Person()
Person.prototype.sayHi = function () { // 对应原型方法在实例化之后调用
  console.log('hi')
}
friend.sayHi() // hi

// 构造函数 + 原型  略  这种模式是一种默认模式
// 动态原型模式
function Person (name, age, job) {
  this.name = name
  this.age = age
  this.job = job
  if (typeof this.sayName !== 'function') {
    Person.prototype.sayName = function () {
      console.log(this.name)
    }
  }
}
var friend = new Person('Nicholas', 29, 'Software Engineer')
friend.sayName() // Nicholas

// 一中不错的写法 
var value = [1, 2, 3]
var value2 = ['lee', 'monkey']
value.push.apply(value, value2)
console.log(value) // [1, 2, 3, "lee", "monkey"]

// 稳妥构造函数模式 跟工厂模式没啥两样,区别在于私有变量没有挂到即将返回的对象o上去,挂上去就是public的
function Person1 (name, age, job) {
  var o = new Object()
  var privite = 'private ' + name
  o. sayName = function () {
    return privite
  }
  return o
}
var friend1 = Person1('Nicholas', 29, 'soft Engineer')
console.log(friend1.sayName()) // private Nicholas